package com.apobates.forum.utils.zxing;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Hashtable;

/**
 * 二维码的主类,有别于com.google.zxing.qrcode.encoder.QRCode
 *
 * @author xiaofanku
 * @since 20200525
 */
public final class GeneralQRCode {
    private final int width;
    private final int height;
    private final ImageType image;
    private final String content;
    
    private GeneralQRCode(String content, int width, int height, ImageType image) {
        this.content = content;
        this.width = width;
        this.height = height;
        this.image = image;
    }
    
    public int getWidth() {
        return width;
    }
    
    public int getHeight() {
        return height;
    }
    
    public ImageType getImage() {
        return image;
    }
    
    public String getContent() {
        return content;
    }
    
    //https://github.com/kenglxn/QRGen/blob/master/javase/src/main/java/net/glxn/qrgen/javase/QRCode.java
    /**
     * 写入到输出文件中
     *
     * @param outputFile 输出文件
     * @throws WriterException
     * @throws IOException
     */
    public void toFile(File outputFile) throws WriterException, IOException {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
        // 默认为ISO-8859-1,若字符串超ASCII可以设置为UTF-8
        // hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); 
        hints.put(EncodeHintType.MARGIN, "1"); //默认为4
        // 1-39级,默认为Encoder.recommendVersion
        // hints.put(EncodeHintType.QR_VERSION, "10"); 
        // 指定生成的数据矩阵的形状(无效果)
        // hints.put(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE);
        // 指定纠错等级(默认:ErrorCorrectionLevel.L)纠正率越高，扫描速度越慢
        // hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); 
        
        BitMatrix bitMatrix = new QRCodeWriter().encode(getContent(), BarcodeFormat.QR_CODE, getWidth(), getHeight(), hints);
        MatrixToImageWriter.writeToPath(bitMatrix, getImage().type, outputFile.toPath());
    }
    
    //https://github.com/zxing/zxing/blob/master/javase/src/main/java/com/google/zxing/client/j2se/MatrixToImageWriter.java
    /**
     * 写入到输出流中
     *
     * @param stream 输出流
     * @throws IOException
     * @throws WriterException
     */
    public void toStream(OutputStream stream) throws IOException, WriterException {
        Hashtable<EncodeHintType, String> hints = new Hashtable<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.MARGIN, "1");
        
        BitMatrix bitMatrix = new QRCodeWriter().encode(getContent(), BarcodeFormat.QR_CODE, getWidth(), getHeight(), hints);
        MatrixToImageWriter.writeToStream(bitMatrix, getImage().type, stream);
    }
    /**
     * 二维码输出的图片类型,支持gif,png,jpeg
     *
     * @author xiaofanku
     * @since 20200326
     */
    public static enum ImageType {
        GIF("gif"), PNG("png"), JPEG("jpeg");
        private final String type;
        
        private ImageType(String type) {
            this.type = type;
        }
        
        public String getType() {
            return type;
        }
    }
    public static class GeneralQRCodeBuilder {
        private int width = 128;
        private int height = 128;
        private ImageType type = ImageType.PNG;
        private final String content;
        
        public GeneralQRCodeBuilder(String content) {
            super();
            this.content = content;
        }
        
        public GeneralQRCodeBuilder withSize(int width, int height) {
            this.width = width;
            this.height = height;
            return this;
        }
        
        public GeneralQRCodeBuilder formatImage(ImageType type) {
            this.type = type;
            return this;
        }
        
        public GeneralQRCode build() {
            return new GeneralQRCode(content, width, height, type);
        }
    }
}